/*
 *  author: Honrun
 */
#include "stm32f4xx_hal.h"
#include "stdint.h"
#include "stdio.h"
#include "string.h"
#include "DevicesUart.h"


uint8_t g_USART1ReadDMABuff[USART1_DMA_READ_LENGTH + 4] = {0};
uint8_t g_USART1SendDMABuff[USART1_DMA_SEND_LENGTH + 4] = {0};
uint8_t g_USART2ReadDMABuff[USART2_DMA_READ_LENGTH + 4] = {0};
uint8_t g_USART2SendDMABuff[USART2_DMA_SEND_LENGTH + 4] = {0};
uint8_t g_USART6ReadDMABuff[USART6_DMA_READ_LENGTH + 4] = {0};
uint8_t g_USART6SendDMABuff[USART6_DMA_SEND_LENGTH + 4] = {0};

UART_HandleTypeDef g_typeUart1Handle;
UART_HandleTypeDef g_typeUart2Handle;
UART_HandleTypeDef g_typeUart6Handle;

DMA_HandleTypeDef g_typeDmaUart1Tx;
DMA_HandleTypeDef g_typeDmaUart1Rx;
DMA_HandleTypeDef g_typeDmaUart2Tx;
DMA_HandleTypeDef g_typeDmaUart2Rx;
DMA_HandleTypeDef g_typeDmaUart6Tx;
DMA_HandleTypeDef g_typeDmaUart6Rx;


void vUart1Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};

    /* Enable peripherals and GPIO Clocks */
    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* Enable USARTx clock */
    __HAL_RCC_USART1_CLK_ENABLE();

    /* Configure peripheral GPIO */
    /* UART TX/RX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_9 | GPIO_PIN_10;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    g_typeUart1Handle.Instance        = USART1;
    g_typeUart1Handle.Init.BaudRate   = 921600;
    g_typeUart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
    g_typeUart1Handle.Init.StopBits   = UART_STOPBITS_1;
    g_typeUart1Handle.Init.Parity     = UART_PARITY_NONE;
    g_typeUart1Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    g_typeUart1Handle.Init.Mode       = UART_MODE_TX_RX;
    g_typeUart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&g_typeUart1Handle);


    vUart1DMAInit(&g_typeUart1Handle);


    /* Enable the UART Complete Interrupt */
    __HAL_UART_ENABLE_IT(&g_typeUart1Handle, UART_IT_IDLE);

    /* NVIC for USART, to catch the RX complete */
    HAL_NVIC_SetPriority(USART1_IRQn, 9, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
}

void vUart2Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};

    /*##-1- Enable peripherals and GPIO Clocks #################################*/
    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOD_CLK_ENABLE();

    /* Enable USARTx clock */
    __HAL_RCC_USART2_CLK_ENABLE();

    /*##-2- Configure peripheral GPIO ##########################################*/
    /* UART TX/RX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_5 | GPIO_PIN_6;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    g_typeUart2Handle.Instance          = USART2;
    g_typeUart2Handle.Init.BaudRate     = 921600;
    g_typeUart2Handle.Init.WordLength   = UART_WORDLENGTH_8B;
    g_typeUart2Handle.Init.StopBits     = UART_STOPBITS_1;
    g_typeUart2Handle.Init.Parity       = UART_PARITY_NONE;
    g_typeUart2Handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    g_typeUart2Handle.Init.Mode         = UART_MODE_TX_RX;
    g_typeUart2Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&g_typeUart2Handle);

    vUart2DMAInit(&g_typeUart2Handle);


    /* Disable the UART Transmit Complete Interrupt */
    __HAL_UART_DISABLE_IT(&g_typeUart2Handle, UART_IT_IDLE);

    /* NVIC for USART, to catch the RX complete */
    HAL_NVIC_SetPriority(USART2_IRQn, 9, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
}

void vUart6Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};

    /*##-1- Enable peripherals and GPIO Clocks #################################*/
    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOC_CLK_ENABLE();

    /* Enable USARTx clock */
    __HAL_RCC_USART6_CLK_ENABLE();

    /*##-2- Configure peripheral GPIO ##########################################*/
    /* UART TX/RX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    g_typeUart6Handle.Instance          = USART6;
    g_typeUart6Handle.Init.BaudRate     = 921600;
    g_typeUart6Handle.Init.WordLength   = UART_WORDLENGTH_8B;
    g_typeUart6Handle.Init.StopBits     = UART_STOPBITS_1;
    g_typeUart6Handle.Init.Parity       = UART_PARITY_NONE;
    g_typeUart6Handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    g_typeUart6Handle.Init.Mode         = UART_MODE_TX_RX;
    g_typeUart6Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&g_typeUart6Handle);


    vUart6DMAInit(&g_typeUart6Handle);


    /* Enable the UART Transmit Complete Interrupt */
    __HAL_UART_ENABLE_IT(&g_typeUart6Handle, UART_IT_IDLE);

    /* NVIC for USART, to catch the RX complete */
    HAL_NVIC_SetPriority(USART6_IRQn, 9, 0);
    HAL_NVIC_EnableIRQ(USART6_IRQn);
}

void vUart1DMAInit(UART_HandleTypeDef *huart)
{
    /* Enable DMA clock */
    __HAL_RCC_DMA2_CLK_ENABLE();

    /* Configure the DMA */
    /* Configure the DMA handler for Transmission process */
    g_typeDmaUart1Tx.Instance                 = DMA2_Stream7;
    HAL_DMA_DeInit(&g_typeDmaUart1Tx);
    g_typeDmaUart1Tx.Init.Channel             = DMA_CHANNEL_4;
    g_typeDmaUart1Tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    g_typeDmaUart1Tx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart1Tx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart1Tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart1Tx.Init.Mode                = DMA_NORMAL;
    g_typeDmaUart1Tx.Init.Priority            = DMA_PRIORITY_LOW;
    g_typeDmaUart1Tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart1Tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart1Tx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart1Tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart1Tx);

    /* Associate the initialized DMA handle to the UART handle */
    __HAL_LINKDMA(huart, hdmatx, g_typeDmaUart1Tx);

    /* Configure the DMA handler for reception process */
    g_typeDmaUart1Rx.Instance                 = DMA2_Stream5;
    HAL_DMA_DeInit(&g_typeDmaUart1Rx);
    g_typeDmaUart1Rx.Init.Channel             = DMA_CHANNEL_4;
    g_typeDmaUart1Rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    g_typeDmaUart1Rx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart1Rx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart1Rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart1Rx.Init.Mode                = DMA_CIRCULAR;
    g_typeDmaUart1Rx.Init.Priority            = DMA_PRIORITY_HIGH;
    g_typeDmaUart1Rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart1Rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart1Rx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart1Rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart1Rx);

    /* Associate the initialized DMA handle to the the UART handle */
    __HAL_LINKDMA(huart, hdmarx, g_typeDmaUart1Rx);


    /* Enable the UART transmit DMA stream */
    HAL_DMA_Start(&g_typeDmaUart1Rx, (uint32_t)(&(USART1->DR)), (uint32_t)g_USART1ReadDMABuff, USART1_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART1->CR3, USART_CR3_DMAR);

    // /* Enable the UART transmit DMA stream */
    // HAL_DMA_Start(&g_typeDmaUart1Tx, (uint32_t)g_USART1ReadDMABuff, (uint32_t)(&(USART1->DR)), USART1_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART1->CR3, USART_CR3_DMAT);
}

/**
  * @brief UART MSP Initialization
  *        This function configures the hardware resources used in this example:
  *           - Peripheral's clock enable
  *           - Peripheral's GPIO Configuration
  *           - DMA configuration for transmission request by peripheral
  *           - NVIC configuration for DMA interrupt request enable
  * @param huart: UART handle pointer
  * @retval None
  */
void vUart2DMAInit(UART_HandleTypeDef *huart)
{
    /* Enable DMA clock */
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* Configure the DMA */
    /* Configure the DMA handler for Transmission process */
    g_typeDmaUart2Tx.Instance                 = DMA1_Stream6;
    g_typeDmaUart2Tx.Init.Channel             = DMA_CHANNEL_4;
    g_typeDmaUart2Tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    g_typeDmaUart2Tx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart2Tx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart2Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart2Tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart2Tx.Init.Mode                = DMA_NORMAL;
    g_typeDmaUart2Tx.Init.Priority            = DMA_PRIORITY_LOW;
    g_typeDmaUart2Tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart2Tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart2Tx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart2Tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart2Tx);

    /* Associate the initialized DMA handle to the UART handle */
    __HAL_LINKDMA(huart, hdmatx, g_typeDmaUart2Tx);

    /* Configure the DMA handler for reception process */
    g_typeDmaUart2Rx.Instance                 = DMA1_Stream5;
    g_typeDmaUart2Rx.Init.Channel             = DMA_CHANNEL_4;
    g_typeDmaUart2Rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    g_typeDmaUart2Rx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart2Rx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart2Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart2Rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart2Rx.Init.Mode                = DMA_CIRCULAR;
    g_typeDmaUart2Rx.Init.Priority            = DMA_PRIORITY_HIGH;
    g_typeDmaUart2Rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart2Rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart2Rx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart2Rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart2Rx);

    /* Associate the initialized DMA handle to the the UART handle */
    __HAL_LINKDMA(huart, hdmarx, g_typeDmaUart2Rx);


    /* Enable the UART transmit DMA stream */
    HAL_DMA_Start(&g_typeDmaUart2Rx, (uint32_t)(&(USART2->DR)), (uint32_t)g_USART2ReadDMABuff, USART2_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART2->CR3, USART_CR3_DMAR);

    // /* Enable the UART transmit DMA stream */
    // HAL_DMA_Start(&g_typeDmaUart1Tx, (uint32_t)g_USART1ReadDMABuff, (uint32_t)(&(USART1->DR)), USART1_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART2->CR3, USART_CR3_DMAT);
}

/**
  * @brief UART MSP Initialization
  *        This function configures the hardware resources used in this example:
  *           - Peripheral's clock enable
  *           - Peripheral's GPIO Configuration
  *           - DMA configuration for transmission request by peripheral
  *           - NVIC configuration for DMA interrupt request enable
  * @param huart: UART handle pointer
  * @retval None
  */
void vUart6DMAInit(UART_HandleTypeDef *huart)
{
    /* Enable DMA clock */
    __HAL_RCC_DMA2_CLK_ENABLE();

    /* Configure the DMA */
    /* Configure the DMA handler for Transmission process */
    g_typeDmaUart6Tx.Instance                 = DMA2_Stream6;
    g_typeDmaUart6Tx.Init.Channel             = DMA_CHANNEL_5;
    g_typeDmaUart6Tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    g_typeDmaUart6Tx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart6Tx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart6Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart6Tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart6Tx.Init.Mode                = DMA_NORMAL;
    g_typeDmaUart6Tx.Init.Priority            = DMA_PRIORITY_LOW;
    g_typeDmaUart6Tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart6Tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart6Tx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart6Tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart6Tx);

    /* Associate the initialized DMA handle to the UART handle */
    __HAL_LINKDMA(huart, hdmatx, g_typeDmaUart6Tx);

    /* Configure the DMA handler for reception process */
    g_typeDmaUart6Rx.Instance                 = DMA2_Stream1;
    g_typeDmaUart6Rx.Init.Channel             = DMA_CHANNEL_5;
    g_typeDmaUart6Rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    g_typeDmaUart6Rx.Init.PeriphInc           = DMA_PINC_DISABLE;
    g_typeDmaUart6Rx.Init.MemInc              = DMA_MINC_ENABLE;
    g_typeDmaUart6Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    g_typeDmaUart6Rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    g_typeDmaUart6Rx.Init.Mode                = DMA_CIRCULAR;
    g_typeDmaUart6Rx.Init.Priority            = DMA_PRIORITY_HIGH;
    g_typeDmaUart6Rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    g_typeDmaUart6Rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    g_typeDmaUart6Rx.Init.MemBurst            = DMA_MBURST_SINGLE;
    g_typeDmaUart6Rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&g_typeDmaUart6Rx);

    /* Associate the initialized DMA handle to the the UART handle */
    __HAL_LINKDMA(huart, hdmarx, g_typeDmaUart6Rx);


    /* Enable the UART transmit DMA stream */
    HAL_DMA_Start(&g_typeDmaUart6Rx, (uint32_t)(&(USART6->DR)), (uint32_t)g_USART6ReadDMABuff, USART6_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART6->CR3, USART_CR3_DMAR);

    // /* Enable the UART transmit DMA stream */
    // HAL_DMA_Start(&g_typeDmaUart1Tx, (uint32_t)g_USART1ReadDMABuff, (uint32_t)(&(USART1->DR)), USART1_DMA_READ_LENGTH);
    /* Enable the DMA transfer for transmit request by setting the DMAT bit in the UART CR3 register */
    SET_BIT(USART6->CR3, USART_CR3_DMAT);
}



void vUartSendDatas(USART_TypeDef* USARTx, uint8_t *pucDatas, int32_t iLength)
{
    uint32_t uiTime = 0;

    while((iLength--) > 0)
    {
        uiTime = 10000;
        /* Loop until the end of transmission */
        while(((USARTx->SR & UART_FLAG_TXE) == RESET) && (--uiTime));

        /* Transmit Data */
        USARTx->DR = *pucDatas++;
    }
}

void vUartSendStrings(USART_TypeDef* USARTx, char *pcStrings)
{
    vUartSendDatas(USARTx, (uint8_t *)pcStrings, strlen(pcStrings));
}





/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
void vDMASetLenthStart(DMA_HandleTypeDef *hdma, uint32_t uiLength)
{
    uint32_t uiTime = 0;

    uiTime = 100000;
    /* Disable the peripheral */
    __HAL_DMA_DISABLE(hdma);
    while(((hdma->Instance->CR & DMA_SxCR_EN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    __HAL_DMA_CLEAR_FLAG(hdma, 0xFFFFFFFF);

    /* Configure DMA Stream data length */
    hdma->Instance->NDTR = uiLength;

    uiTime = 100000;
    /* Enable the peripheral */
    __HAL_DMA_ENABLE(hdma);
    while(((hdma->Instance->CR & DMA_SxCR_EN) == 0) && (--uiTime));
}

/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
void vDMAMultiBufferSetLenthStart(DMA_HandleTypeDef *hdma, uint32_t uiLength)
{
    uint32_t uiTime = 0;

    uiTime = 100000;
    /* Disable the peripheral */
    __HAL_DMA_DISABLE(hdma);
    while(((hdma->Instance->CR & DMA_SxCR_EN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    __HAL_DMA_CLEAR_FLAG(hdma, 0xFFFFFFFF);

    /* Configure DMA Stream data length */
    hdma->Instance->NDTR = uiLength;

    /* 切换DMA双缓存指针 */
    hdma->Instance->CR ^= DMA_SxCR_CT;

    uiTime = 100000;
    /* Enable the peripheral */
    __HAL_DMA_ENABLE(hdma);
    while(((hdma->Instance->CR & DMA_SxCR_EN) == 0) && (--uiTime));
}


/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
void vDMASetAddrAndLenthStart(DMA_HandleTypeDef *hdma, uint32_t uiSourceAddress, uint32_t uiTargetAddress, uint32_t uiLength)
{
    uint32_t uiTime = 0;

    uiTime = 100000;
    /* Disable the peripheral */
    __HAL_DMA_DISABLE(hdma);
    while(((hdma->Instance->CR & DMA_SxCR_EN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    __HAL_DMA_CLEAR_FLAG(hdma, 0xFFFFFFFF);

    /* Configure DMA Stream data length */
    hdma->Instance->NDTR = uiLength;

    /* Memory to Peripheral */
    if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
    {
        /* Configure DMA Stream destination address */
        hdma->Instance->PAR = uiTargetAddress;

        /* Configure DMA Stream source address */
        hdma->Instance->M0AR = uiSourceAddress;
    }
    /* Peripheral to Memory */
    else
    {
        /* Configure DMA Stream source address */
        hdma->Instance->PAR = uiSourceAddress;

        /* Configure DMA Stream destination address */
        hdma->Instance->M0AR = uiTargetAddress;
    }

    uiTime = 100000;
    /* Enable the Peripheral */
    __HAL_DMA_ENABLE(hdma);
    /* Wait Enable the peripheral */
    while(((hdma->Instance->CR & DMA_SxCR_EN) == 0) && (--uiTime));
}

void vUartDMASendDatas(USART_TypeDef* USARTx, uint8_t *pucDatas, int32_t iLength)
{
    DMA_HandleTypeDef *hDMAHandle = NULL;
    uint32_t uiDMAISRFlag = 0;
    int32_t iDMAMaxLength = 0;
    uint8_t *pucSendDatasHandle = NULL;


    if(iLength <= 0)
        return;

    switch((uint32_t)USARTx)
    {
        case (uint32_t)USART1: hDMAHandle = &g_typeDmaUart1Tx; uiDMAISRFlag = DMA_FLAG_TCIF3_7; pucSendDatasHandle = g_USART1SendDMABuff; iDMAMaxLength = USART1_DMA_SEND_LENGTH; break;
        case (uint32_t)USART2: hDMAHandle = &g_typeDmaUart2Tx; uiDMAISRFlag = DMA_FLAG_TCIF2_6; pucSendDatasHandle = g_USART2SendDMABuff; iDMAMaxLength = USART2_DMA_SEND_LENGTH; break;
        case (uint32_t)USART6: hDMAHandle = &g_typeDmaUart6Tx; uiDMAISRFlag = DMA_FLAG_TCIF2_6; pucSendDatasHandle = g_USART6SendDMABuff; iDMAMaxLength = USART6_DMA_SEND_LENGTH; break;

        default : printf("vUartDMASendDatas channel error.\r\n"); return;
    }

    /* 等待上次DMA传输完成 */
    while((__HAL_DMA_GET_FLAG(hDMAHandle, uiDMAISRFlag) == RESET) && ((hDMAHandle->Instance->CR & DMA_SxCR_EN) != 0));

    /* 方式1：充分利用DMA不占用CPU的时间 */
    if(iLength <= iDMAMaxLength)
    {
        memcpy(pucSendDatasHandle, pucDatas, iLength);

        /* 设置传输地址与长度，并启动DMA发送 */
        vDMASetAddrAndLenthStart(hDMAHandle, (uint32_t)pucSendDatasHandle, (uint32_t)(&(USARTx->DR)), iLength);
    }
    /* 方式2：发送后再等待，防止发送的数据缓存被之后的代码更改 */
    else
    {
        /* 设置传输地址与长度，并启动DMA发送 */
        vDMASetAddrAndLenthStart(hDMAHandle, (uint32_t)pucDatas, (uint32_t)(&(USARTx->DR)), iLength);

        /* 等待本次DMA传输完成 */
        while((__HAL_DMA_GET_FLAG(hDMAHandle, uiDMAISRFlag) == RESET) && ((hDMAHandle->Instance->CR & DMA_SxCR_EN) != 0));
    }
}

void vUartDMASendStrings(USART_TypeDef* USARTx, char *pcStrings)
{
    vUartDMASendDatas(USARTx, (uint8_t *)pcStrings, strlen(pcStrings));
}
